package constraints

import (
	"sort"
	"sync"
)

func NewList[V comparable]() (obj *List[V]) {
	obj = &List[V]{}
	return
}

type List[V comparable] struct {
	data []V

	mutex        sync.RWMutex
	mutexLocked  bool
	mutexRLocked bool
}

func (list *List[V]) rlock() {
	if list.mutexLocked || list.mutexRLocked {
		return
	}
	list.mutex.RLock()
	list.mutexRLocked = true
}
func (list *List[V]) runlock() {
	if !list.mutexRLocked {
		return
	}
	if list.mutexRLocked {
		return
	}
	list.mutex.RUnlock()
	list.mutexRLocked = false
}
func (list *List[V]) lock() {
	if list.mutexLocked || list.mutexRLocked {
		return
	}
	list.mutex.Lock()
	list.mutexLocked = true
}
func (list *List[V]) unlock() {
	if !list.mutexLocked {
		return
	}
	if list.mutexRLocked {
		return
	}
	list.mutex.Unlock()
	list.mutexLocked = false
}

// Add 添加元素, 如果已存在, 不添加
func (list *List[V]) Add(items ...V) {
	list.lock()
	for _, item := range items {
		if list.Contains(item) {
			return
		}
		list.data = append(list.data, item)
	}
	list.unlock()
}

// AddConf 添加元素, 如果已存在相同条件[conf]的项, 不添加
func (list *List[V]) AddConf(cond func(index int, item V) bool, items ...V) {
	list.lock()
	for _, item := range items {
		if list.ContainsCond(cond) {
			return
		}
		list.data = append(list.data, item)
	}
	list.unlock()
}

func (list *List[V]) Set(index int, val V) {
	// 索引的读写是并发安全的
	list.data[index] = val
}

func (list *List[V]) SetList(val []V) {
	list.lock()
	list.data = val
	list.unlock()
}

func (list *List[V]) At(index int) (result V) {
	if index < 0 {
		return
	}
	if index >= list.Length() {
		return
	}
	return list.data[index]
}

func (list *List[V]) Clear() {
	list.lock()
	list.data = []V{}
	list.unlock()
}

func (list *List[V]) Dispose() {
	list.lock()
	list.data = nil
	list.unlock()
}

func (list *List[V]) Clone() *List[V] {
	list.lock()
	s := list.data
	ss := make([]V, len(s), cap(s))
	copy(ss, s)
	list.unlock()
	return &List[V]{data: ss}
}

func (list *List[V]) Contains(item V) bool {
	return list.IndexOf(item) != -1
}

func (list *List[V]) ContainsCond(cond func(index int, item V) bool) bool {
	return list.IndexOfConf(cond) != -1
}

// CountCond 按照条件计数
func (list *List[V]) CountCond(cond func(index int, item V) bool) int {
	list.rlock()
	c := 0
	s := list.data
	for i := 0; i < len(s); i++ {
		if cond(i, s[i]) {
			c++
		}
	}
	list.runlock()

	return c
}

// Every 每一个项都符合条件就返回true
func (list *List[V]) Every(cond func(index int, item V) bool) bool {
	list.lock()
	//defer list.unlock()

	s := list.data
	for i := 0; i < len(s); i++ {
		val := s[i]
		if cond(i, val) == false {
			return false
		}
	}
	list.runlock()
	return true
}

func (list *List[V]) First(cond func(index int, item V) bool) (val V, has bool) {
	list.rlock()
	s := list.data
	for i := 0; i < len(s); i++ {
		v := s[i]
		if cond(i, v) {
			return v, true
		}
	}
	list.runlock()
	return
}

// 返回符合条件的项形成的新列表
func (list *List[V]) Filter(cond func(index int, item V) bool) *List[V] {
	list.rlock()
	var a []V
	for i, x := range list.data {
		if cond(i, x) {
			a = append(a, x)
		}
	}
	list.runlock()
	return &List[V]{data: a}
}

// 如果返回错误，迭代终止
func (list *List[V]) ForRange(handler func(index int, item V) error) {
	list.lock()
	for i, x := range list.data {
		a := x
		if handler(i, a) != nil {
			list.unlock()
			return
		}
	}
	list.unlock()
}

// 从最后往前开始遍历
// 如果返回错误，迭代终止
func (list *List[V]) ForRangeFromLast(handler func(index int, item V) error) {
	list.lock()
	s := list.data
	for i := len(s) - 1; i >= 0; i-- {
		a := s[i]
		if handler(i, a) != nil {
			list.unlock()
			return
		}
	}
	list.unlock()
}

// 返回符合条件的项的索引
func (list *List[V]) IndexOfConf(cond func(index int, item V) bool) int {
	list.rlock()
	s := list.data
	for i := 0; i < len(s); i++ {
		if cond(i, s[i]) {
			return i
		}
	}
	list.runlock()
	return -1
}

// 返回项的索引
func (list *List[V]) IndexOf(item V) int {
	list.rlock()
	s := list.data
	for i := 0; i < len(s); i++ {
		if s[i] == item {
			return i
		}
	}
	list.runlock()
	return -1
}

func (list *List[V]) Last(cond func(index int, item V) bool) (result V, has bool) {
	list.rlock()
	s := list.data
	for i := len(s) - 1; i >= 0; i-- {
		val := s[i]
		if cond(i, val) {
			return val, true
		}
	}
	list.runlock()
	return
}

func (list *List[V]) Length() int {
	return len(list.data)
}

func (list *List[V]) Pop() V {
	list.lock()

	s := list.data
	last := s[len(s)-1] // 索引的读写是并发安全的
	var zero V
	s[len(s)-1] = zero // GC
	s2 := s[:len(s)-1]
	list.data = s2

	list.unlock()
	return last
}

func (list *List[V]) Push(item V) {
	list.lock()
	list.push(item)
	list.unlock()
}

func (list *List[V]) push(item V) {
	list.data = append(list.data, item)
}

func (list *List[V]) PushList(val IList[V]) {
	list.lock()
	list.pushList(val)
	list.unlock()
}

func (list *List[V]) pushList(val IList[V]) {
	s := list.data
	s = append(s, val.Slice()...)
	list.data = s
}

func (list *List[V]) Remove(item V) {
	i := list.IndexOf(item)
	if i != -1 {
		list.RemoveAt(i)
	}
}

func (list *List[V]) RemoveAt(i int) {
	list.lock()

	s := list.data
	copy(s[i:], s[i+1:])
	var zero V
	s[len(s)-1] = zero // GC
	s2 := s[:len(s)-1]
	list.data = s2

	list.unlock()
}

func (list *List[V]) Replace(i int, item V) {
	list.lock()

	s := list.data
	over := i - len(s)
	if over > -1 {
		ss := make([]V, i+1)
		copy(ss[0:], s[:])
		s = ss
	}
	s[i] = item
	list.data = s

	list.unlock()
}

func (list *List[V]) Insert(i int, item V) {
	list.lock()

	s := list.data
	var zero V
	s = append(s, zero /* use the zero value of the element type */)
	copy(s[i+1:], s[i:])
	s[i] = item
	list.data = s

	list.unlock()
}

func (list *List[V]) Reverse() {
	list.lock()

	s := list.data
	for i := len(s)/2 - 1; i >= 0; i-- {
		opp := len(s) - 1 - i
		s[i], s[opp] = s[opp], s[i]
	}

	list.unlock()
}

func (list *List[V]) Shift() V {
	list.lock()

	s := list.data
	top := s[0]
	var zero V
	s[0] = zero // GC
	s2 := s[1:]
	list.data = s2

	list.unlock()
	return top
}

// Slice 直接返回slice值
func (list *List[V]) Slice() []V {
	return list.data
}

// Self 返回自身的列表
// 用于List作为组合时的快捷方式
func (list *List[V]) Self() *List[V] {
	return list
}

// compare返回值：>=0 a排b前面
func (list *List[V]) Sort(compare func(a, b V) int) {
	list.lock()
	l := list.data
	sort.Slice(l, func(i, j int) bool {
		return compare(l[i], l[j]) >= 0
	})
	list.unlock()
}

func (list *List[V]) Unshift(item V) {
	list.lock()

	s := list.data
	l := len(s) + 1
	ss := make([]V, l, l)
	ss[0] = item
	copy(ss[1:], s[:])
	list.data = ss

	list.unlock()
}

// Unique 去重操作, 返回去重后的数组
func (list *List[V]) Unique() *List[V] {
	list.lock()
	l := list.unique()
	list.unlock()
	return l
}

func (list *List[V]) unique() *List[V] {
	var r []V
	l := list.data
	m := map[V]struct{}{} // 存放不重复主键
	for _, e := range l {
		length := len(m)
		m[e] = struct{}{}
		if len(m) != length { // 加入map后，map长度变化，则元素不重复
			r = append(r, e)
		}
	}

	return &List[V]{data: r}
}

// UniqueByCustomKey 去重操作, 返回去重后的数组
// 自定义键值
func (list *List[V]) UniqueByCustomKey(getKey func(item V) string) *List[V] {
	list.lock()
	l := list.uniqueByCustomKey(getKey)
	list.unlock()
	return l
}

func (list *List[V]) uniqueByCustomKey(getKey func(item V) string) *List[V] {
	var r []V
	l := list.data
	m := map[string]struct{}{} // 存放不重复主键
	for _, e := range l {
		length := len(m)
		m[getKey(e)] = struct{}{}
		if len(m) != length { // 加入map后，map长度变化，则元素不重复
			r = append(r, e)
		}
	}
	return &List[V]{data: r}
}

// Union 并集
func (list *List[V]) Union(a IList[V]) *List[V] {
	list.lock()
	list.pushList(a)
	l := list.unique()
	list.unlock()
	return l
}

// UnionByCustomKey 并集
func (list *List[V]) UnionByCustomKey(a IList[V], getKey func(item V) string) *List[V] {
	list.lock()
	list.pushList(a)
	return list.UniqueByCustomKey(getKey)
}

// 交集
//func Intersect[T comparable](arrs ...[]T) []T {
//	m := make(map[T]int)
//
//	var (
//		tmpArr []T
//		count  int
//		ok     bool
//	)
//	for idx1 := range arrs {
//		tmpArr = Distinct(arrs[idx1])
//
//		for idx2 := range tmpArr {
//			count, ok = m[tmpArr[idx2]]
//			if !ok {
//				m[tmpArr[idx2]] = 1
//			} else {
//				m[tmpArr[idx2]] = count + 1
//			}
//		}
//	}
//
//	var (
//		ret     []T
//		lenArrs int = len(arrs)
//	)
//	for k, v := range m {
//		if v == lenArrs {
//			ret = append(ret, k)
//		}
//	}
//
//	return ret
//}
